<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Chapter 20. Zend_InfoCard</title>
<link rel="stylesheet" href="dbstyle.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.72.0">
<link rel="start" href="index.html" title="Programmer's Reference Guide">
<link rel="up" href="index.html" title="Programmer's Reference Guide">
<link rel="prev" href="zend.http.response.html" title="19.5. Zend_Http_Response">
<link rel="next" href="zend.json.html" title="Chapter 21. Zend_Json">
<link rel="chapter" href="introduction.html" title="Chapter 1. Introduction to Zend Framework">
<link rel="chapter" href="zend.acl.html" title="Chapter 2. Zend_Acl">
<link rel="chapter" href="zend.auth.html" title="Chapter 3. Zend_Auth">
<link rel="chapter" href="zend.cache.html" title="Chapter 4. Zend_Cache">
<link rel="chapter" href="zend.config.html" title="Chapter 5. Zend_Config">
<link rel="chapter" href="zend.console.getopt.html" title="Chapter 6. Zend_Console_Getopt">
<link rel="chapter" href="zend.controller.html" title="Chapter 7. Zend_Controller">
<link rel="chapter" href="zend.currency.html" title="Chapter 8. Zend_Currency">
<link rel="chapter" href="zend.date.html" title="Chapter 9. Zend_Date">
<link rel="chapter" href="zend.db.html" title="Chapter 10. Zend_Db">
<link rel="chapter" href="zend.debug.html" title="Chapter 11. Zend_Debug">
<link rel="chapter" href="zend.dojo.html" title="Chapter 12. Zend_Dojo">
<link rel="chapter" href="zend.dom.html" title="Chapter 13. Zend_Dom">
<link rel="chapter" href="zend.exception.html" title="Chapter 14. Zend_Exception">
<link rel="chapter" href="zend.feed.html" title="Chapter 15. Zend_Feed">
<link rel="chapter" href="zend.filter.html" title="Chapter 16. Zend_Filter">
<link rel="chapter" href="zend.form.html" title="Chapter 17. Zend_Form">
<link rel="chapter" href="zend.gdata.html" title="Chapter 18. Zend_Gdata">
<link rel="chapter" href="zend.http.html" title="Chapter 19. Zend_Http">
<link rel="chapter" href="zend.infocard.html" title="Chapter 20. Zend_InfoCard">
<link rel="chapter" href="zend.json.html" title="Chapter 21. Zend_Json">
<link rel="chapter" href="zend.layout.html" title="Chapter 22. Zend_Layout">
<link rel="chapter" href="zend.ldap.html" title="Chapter 23. Zend_Ldap">
<link rel="chapter" href="zend.loader.html" title="Chapter 24. Zend_Loader">
<link rel="chapter" href="zend.locale.html" title="Chapter 25. Zend_Locale">
<link rel="chapter" href="zend.log.html" title="Chapter 26. Zend_Log">
<link rel="chapter" href="zend.mail.html" title="Chapter 27. Zend_Mail">
<link rel="chapter" href="zend.measure.html" title="Chapter 28. Zend_Measure">
<link rel="chapter" href="zend.memory.html" title="Chapter 29. Zend_Memory">
<link rel="chapter" href="zend.mime.html" title="Chapter 30. Zend_Mime">
<link rel="chapter" href="zend.openid.html" title="Chapter 31. Zend_OpenId">
<link rel="chapter" href="zend.paginator.html" title="Chapter 32. Zend_Paginator">
<link rel="chapter" href="zend.pdf.html" title="Chapter 33. Zend_Pdf">
<link rel="chapter" href="zend.registry.html" title="Chapter 34. Zend_Registry">
<link rel="chapter" href="zend.rest.html" title="Chapter 35. Zend_Rest">
<link rel="chapter" href="zend.search.lucene.html" title="Chapter 36. Zend_Search_Lucene">
<link rel="chapter" href="zend.server.html" title="Chapter 37. Zend_Server">
<link rel="chapter" href="zend.service.html" title="Chapter 38. Zend_Service">
<link rel="chapter" href="zend.session.html" title="Chapter 39. Zend_Session">
<link rel="chapter" href="zend.soap.html" title="Chapter 40. Zend_Soap">
<link rel="chapter" href="zend.test.html" title="Chapter 41. Zend_Test">
<link rel="chapter" href="zend.text.html" title="Chapter 42. Zend_Text">
<link rel="chapter" href="zend.timesync.html" title="Chapter 43. Zend_TimeSync">
<link rel="chapter" href="zend.translate.html" title="Chapter 44. Zend_Translate">
<link rel="chapter" href="zend.uri.html" title="Chapter 45. Zend_Uri">
<link rel="chapter" href="zend.validate.html" title="Chapter 46. Zend_Validate">
<link rel="chapter" href="zend.version.html" title="Chapter 47. Zend_Version">
<link rel="chapter" href="zend.view.html" title="Chapter 48. Zend_View">
<link rel="chapter" href="zend.xmlrpc.html" title="Chapter 49. Zend_XmlRpc">
<link rel="appendix" href="requirements.html" title="Appendix A. Zend Framework Requirements">
<link rel="appendix" href="coding-standard.html" title="Appendix B. Zend Framework Coding Standard for PHP">
<link rel="appendix" href="copyrights.html" title="Appendix C. Copyright Information">
<link rel="index" href="the.index.html" title="Index">
<link rel="section" href="zend.infocard.html#zend.infocard.basics" title="20.1. Introduction">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<div class="navheader"><table width="100%" summary="Navigation header">
<tr><th colspan="3" align="center">Chapter 20. Zend_InfoCard</th></tr>
<tr>
<td width="20%" align="left">
<a accesskey="p" href="zend.http.response.html">Prev</a> </td>
<th width="60%" align="center"> </th>
<td width="20%" align="right"> <a accesskey="n" href="zend.json.html">Next</a>
</td>
</tr>
</table></div>
<div class="chapter" lang="en">
<div class="titlepage"><div><div><h2 class="title">
<a name="zend.infocard"></a>Chapter 20. Zend_InfoCard</h2></div></div></div>
<div class="toc">
<p><b>Table of Contents</b></p>
<dl>
<dt><span class="sect1"><a href="zend.infocard.html#zend.infocard.basics">20.1. Introduction</a></span></dt>
<dd><dl>
<dt><span class="sect2"><a href="zend.infocard.html#zend.infocard.basics.theory">20.1.1. Basic Theory of Usage</a></span></dt>
<dt><span class="sect2"><a href="zend.infocard.html#zend.infocard.basics.auth">20.1.2. Using as part of Zend_Auth</a></span></dt>
<dt><span class="sect2"><a href="zend.infocard.html#zend.infocard.basics.standalone">20.1.3. Using the Zend_InfoCard component standalone</a></span></dt>
<dt><span class="sect2"><a href="zend.infocard.html#zend.infocard.basics.claims">20.1.4. Working with a Claims object</a></span></dt>
<dt><span class="sect2"><a href="zend.infocard.html#zend.infocard.basics.attaching">20.1.5. Attaching Information Cards to existing accounts</a></span></dt>
<dt><span class="sect2"><a href="zend.infocard.html#zend.infocard.basics.adapters">20.1.6. Creating Zend_InfoCard adapters</a></span></dt>
</dl></dd>
</dl>
</div>
<div class="sect1" lang="en">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="zend.infocard.basics"></a>20.1. Introduction</h2></div></div></div>
<p>
        The <code class="code">Zend_InfoCard</code> component implements relying-party
        support for Information Cards.  Infomation Cards are used for identity
        management on the internet and authentication of users to web sites
        (called relying parties). 
    </p>
<p>
        Detailed information about information cards and their importance to the
        internet identity metasystem can be found on the <a href="http://www.identityblog.com/" target="_top">IdentityBlog</a>
    </p>
<div class="sect2" lang="en">
<div class="titlepage"><div><div><h3 class="title">
<a name="zend.infocard.basics.theory"></a>20.1.1. Basic Theory of Usage</h3></div></div></div>
<p>
            Usage of <code class="code">Zend_InfoCard</code> can be done one of two ways:
            either as part of the larger <code class="code">Zend_Auth</code> component via
            the <code class="code">Zend_InfoCard</code> authentication adapter or as a
            stand-alone component. In both cases an information card can be
            requested from a user by using the following HTML block in your HTML
            login form:
        </p>
<pre class="programlisting">
&lt;form action="http://example.com/server" method="POST"&gt;
  &lt;input type='image' src='/images/ic.png' align='center' 
        width='120px' style='cursor:pointer' /&gt;
  &lt;object type="application/x-informationCard" 
          name="xmlToken"&gt;
   &lt;param name="tokenType" 
         value="urn:oasis:names:tc:SAML:1.0:assertion" /&gt;
   &lt;param name="requiredClaims" 
         value="http://.../claims/privatepersonalidentifier 
         http://.../claims/givenname 
         http://.../claims/surname" /&gt;
 &lt;/object&gt;
&lt;/form&gt;
    </pre>
<p>
            In the example above, the <code class="code">requiredClaims</code>
            <code class="code">&lt;param&gt;</code> tag is used to identify pieces of
            information known as claims (i.e. person's first name, last name)
            which the web site (a.k.a "relying party") needs in order a user to
            authenticate using an information card. For your reference, the full
            URI (for instance the <code class="code">givenname</code> claim) is as follows:
            <code class="code">http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname</code>
        </p>
<p>
            When the above HTML is activated by a user (clicks on it), the
            browser will bring up a card selection program which not only shows
            them which information cards meet the requirements of the site, but
            also allows them to select which information card to use if multiple
            meet the criteria. This information card is transmitted as an XML
            document to the specified <code class="code">POST</code> URL and is ready to be
            processed by the <code class="code">Zend_InfoCard</code> component.
        </p>
<p>
            Note, Information cards can only be <code class="code">HTTP POST</code>ed to
            SSL-encrypted URLs. Please consult your web server's documentation
            on how to set up SSL encryption.
        </p>
</div>
<div class="sect2" lang="en">
<div class="titlepage"><div><div><h3 class="title">
<a name="zend.infocard.basics.auth"></a>20.1.2. Using as part of Zend_Auth</h3></div></div></div>
<p>
            In order to use the component as part of the <code class="code">Zend_Auth</code>
            authentication system, you must use the provided
            <code class="code">Zend_Auth_Adapter_InfoCard</code> to do so (not available in
            the standalone <code class="code">Zend_InfoCard</code> distribution). An example
            of its usage is shown below:
        </p>
<pre class="programlisting">&lt;?php
require_once 'Zend/InfoCard/Auth/Adapter.php';
require_once 'Zend/Auth.php';

if (isset($_POST['xmlToken'])) {

    $adapter = new Zend_Auth_Adapter_InfoCard($_POST['xmlToken']);
    
    $adapter-&gt;addCertificatePair('/usr/local/Zend/apache2/conf/server.key',
                                 '/usr/local/Zend/apache2/conf/server.crt');
    
    
    $auth = Zend_Auth::getInstance();
    
    $result = $auth-&gt;authenticate($adapter);
    
    switch ($result-&gt;getCode()) {
        case Zend_Auth_Result::SUCCESS:
            $claims = $result-&gt;getIdentity();
            print "Given Name: {$claims-&gt;givenname}&lt;br /&gt;";
            print "Surname: {$claims-&gt;surname}&lt;br /&gt;";
            print "Email Address: {$claims-&gt;emailaddress}&lt;br /&gt;";
            print "PPI: {$claims-&gt;getCardID()}&lt;br /&gt;";
            break;
        case Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID:
            print "The Credential you provided did not pass validation";
            break;
        default:
        case Zend_Auth_Result::FAILURE:
            print "There was an error processing your credentials.";
            break;
    }
    
    if (count($result-&gt;getMessages()) &gt; 0) {
        print "&lt;pre&gt;";
        var_dump($result-&gt;getMessages());
        print "&lt;/pre&gt;";
    }
    
    
}

?&gt;
&lt;hr /&gt;
&lt;div id="login" style="font-family: arial; font-size: 2em;"&gt;
&lt;p&gt;Simple Login Demo&lt;/p&gt;
 &lt;form method="post"&gt;
  &lt;input type="submit" value="Login" /&gt;
   &lt;object type="application/x-informationCard" name="xmlToken"&gt;
    &lt;param name="tokenType" 
          value="urn:oasis:names:tc:SAML:1.0:assertion" /&gt;
    &lt;param name="requiredClaims" 
          value="http://.../claims/givenname 
                 http://.../claims/surname 
                 http://.../claims/emailaddress 
                 http://.../claims/privatepersonalidentifier" /&gt;
  &lt;/object&gt;
 &lt;/form&gt;
&lt;/div&gt;
</pre>
<p>
            In the example above, we first create an instance of the
            <code class="code">Zend_Auth_Adapter_InfoCard</code> and pass the XML data posted
            by the card selector into it. Once an instance has been created you
            must then provide at least one SSL certificate public/private key
            pair used by the web server which received the <code class="code">HTTP
                POST</code>.  These files are used to validate the destination
            of the information posted to the server and are a requirement when
            using Information Cards. 
        </p>
<p>
            Once the adapter has been configured you can then use the standard
            <code class="code">Zend_Auth</code> facilities to validate the provided
            information card token and authenticate the user by examining the
            identity provided by the <code class="code">getIdentity()</code> method.
        </p>
</div>
<div class="sect2" lang="en">
<div class="titlepage"><div><div><h3 class="title">
<a name="zend.infocard.basics.standalone"></a>20.1.3. Using the Zend_InfoCard component standalone</h3></div></div></div>
<p>
            It is also possible to use the Zend_InfoCard component as a
            standalone component by interacting with the
            <code class="code">Zend_InfoCard</code> class directly. Using the Zend_InfoCard
            class is very similar to its use with the <code class="code">Zend_Auth</code>
            component. An example of its use is shown below:
        </p>
<pre class="programlisting">&lt;?php
require_once 'Zend/InfoCard.php';

if (isset($_POST['xmlToken'])) {
    $infocard = new Zend_InfoCard();
    $infocard-&gt;addCertificatePair('/usr/local/Zend/apache2/conf/server.key',
                                   '/usr/local/Zend/apache2/conf/server.crt');

    $claims = $infocard-&gt;process($_POST['xmlToken']);
    
    if($claims-&gt;isValid()) {
        print "Given Name: {$claims-&gt;givenname}&lt;br /&gt;";
        print "Surname: {$claims-&gt;surname}&lt;br /&gt;";
        print "Email Address: {$claims-&gt;emailaddress}&lt;br /&gt;";
        print "PPI: {$claims-&gt;getCardID()}&lt;br /&gt;";
    } else {
        print "Error Validating identity: {$claims-&gt;getErrorMsg()}";
    }
}

?&gt;
&lt;hr /&gt;
&lt;div id="login" style="font-family: arial; font-size: 2em;"&gt;
 &lt;p&gt;Simple Login Demo&lt;/p&gt;
 &lt;form method="post"&gt;
  &lt;input type="submit" value="Login" /&gt;
   &lt;object type="application/x-informationCard" name="xmlToken"&gt;
    &lt;param name="tokenType" 
          value="urn:oasis:names:tc:SAML:1.0:assertion" /&gt;
    &lt;param name="requiredClaims" 
          value="http://.../claims/givenname 
                 http://.../claims/surname 
                 http://.../claims/emailaddress 
                 http://.../claims/privatepersonalidentifier" /&gt;
   &lt;/object&gt;
 &lt;/form&gt;
&lt;/div&gt;
</pre>
<p>
            In the example above we use the <code class="code">Zend_InfoCard</code> component
            indepdently to validate the token provided by the user. As was the
            case with the <code class="code">Zend_Auth_Adapter_InfoCard</code>, we create an
            instance of <code class="code">Zend_InfoCard</code> and then set one or more SSL
            certificate public/private key pairs used by the web server. Once
            configured we can use the <code class="code">process()</code> method to process
            the information card and return the results
        </p>
</div>
<div class="sect2" lang="en">
<div class="titlepage"><div><div><h3 class="title">
<a name="zend.infocard.basics.claims"></a>20.1.4. Working with a Claims object</h3></div></div></div>
<p>
            Regardless of if the <code class="code">Zend_InfoCard</code> component is used as
            a standalone component or as part of <code class="code">Zend_Auth</code> via the
            <code class="code">Zend_Auth_Adapter_InfoCard</code>, in both cases the ultimate
            result of the processing of an information card is a
            <code class="code">Zend_InfoCard_Claims</code> object. This object contains the
            assertions (a.k.a. claims) made by the submitting user based on the
            data requested by your web site when the user authenticated. As
            shown in the examples above, the validitiy of the information card
            can be ascertained by calling the
            <code class="code">Zend_InfoCard_Claims::isVaild()</code> method. Claims
            themselves can either be retrieved by simply accessing the
            identifier desired (i.e. <code class="code">givenname</code>) as a property of
            the object or through the <code class="code">getClaim()</code> method. 
        </p>
<p>
            In most cases you will never need to use the <code class="code">getClaim()</code>
            method. However, if your <code class="code">requiredClaims</code> mandate that
            you request claims from multiple different sources/namespaces then
            you will need to extract them explictally using this method (simply
            pass it the full URI of the claim to retrieve its value from within
            the information card). Generally speaking however, the
            <code class="code">Zend_InfoCard</code> component will set the default URI for
            claims to be the one used the most frequently within the information
            card itself and the simplified property-access method can be used.
        </p>
<p>
            As part of the validation process, it is up to the developer to
            examine the issuing source of the claims contained within the
            information card and decide if that source is a trusted source of
            information. To do so, the <code class="code">getIssuer()</code> method is
            provided within the <code class="code">Zend_InfoCard_Claims</code> object which
            returns the URI of the issuer of the information card claims.
        </p>
</div>
<div class="sect2" lang="en">
<div class="titlepage"><div><div><h3 class="title">
<a name="zend.infocard.basics.attaching"></a>20.1.5. Attaching Information Cards to existing accounts</h3></div></div></div>
<p>
            It is possible to add support for information cards to an existing
            authentication system by storing the private personal identifier
            (PPI) to a previously traditionally-authenticated account and
            including at least the
            <code class="code">http://schemas.xmlsoap.org/ws/2005/05/identity/claims/privatepersonalidentifier</code>
            claim as part of the <code class="code">requiredClaims</code> of the request. If
            this claim is requested then the <code class="code">Zend_InfoCard_Claims</code>
            object will provide a unique identifier for the specific card that
            was submitted by calling the <code class="code">getCardID()</code> method.
        </p>
<p>
            An example of how to attach an information card to an existing
            traditional-authentication account is shown below:
        </p>
<pre class="programlisting">&lt;?php
// ... 
public function submitinfocardAction() 
{
    if (!isset($_REQUEST['xmlToken'])) {
        throw new ZBlog_Exception("Expected an encrypted token but was not provided");
    }
    
    $infoCard = new Zend_InfoCard();
    $infoCard-&gt;addCertificatePair(SSL_CERTIFICATE_PRIVATE, SSL_CERTIFICATE_PUB);
    
    try {
        $claims = $infoCard-&gt;process($request['xmlToken']);
    } catch(Zend_InfoCard_Exception $e) {
        // TODO Error processing your request
        throw $e;
    }
    
    if ($claims-&gt;isValid()) {
        $db = ZBlog_Data::getAdapter();

        $ppi = $db-&gt;quote($claims-&gt;getCardID());
        $fullname = $db-&gt;quote("{$claims-&gt;givenname} {$claims-&gt;surname}");
        
        $query = "UPDATE blogusers 
                     SET ppi = $ppi, 
                         real_name = $fullname 
                   WHERE username='administrator'";
        
        try {
            $db-&gt;query($query);
        } catch(Exception $e) {
            // TODO Failed to store in DB
        }
        
        $this-&gt;view-&gt;render();
        return;
    } else {
        throw new ZBlog_Exception("Infomation card failed security checks");
    }
}
?&gt;</pre>
</div>
<div class="sect2" lang="en">
<div class="titlepage"><div><div><h3 class="title">
<a name="zend.infocard.basics.adapters"></a>20.1.6. Creating Zend_InfoCard adapters</h3></div></div></div>
<p>
            The <code class="code">Zend_InfoCard</code> component was designed to allow for
            growth in the information card standard through the use of a modular
            architecture. At this time many of these hooks are unused and can be
            ignored, however there is one aspect which should be implemented in
            any serious information card implementation: The
            <code class="code">Zend_InfoCard_Adapter</code>.
        </p>
<p>
            The <code class="code">Zend_InfoCard</code> adapter is used as a callback
            mechanism within the component to perform various tasks, such as
            storing and retrieving Assertion IDs for information cards when they
            are processed by the component.  While storing the assertion IDs of
            submitted information cards is not necessary, failing to do so opens
            up the possibility of the authentication scheme being compromised
            through a replay attack. 
        </p>
<p>
            To prevent this, one must implement the
            <code class="code">Zend_InfoCard_Adapter_Interface</code> and then set an
            instance of this interface prior to calling either the
            <code class="code">process()</code> (standalone) or <code class="code">authenticate()</code>
            method (as a <code class="code">Zend_Auth</code> adapter. To set this interface
            the <code class="code">setAdapter()</code> method is used. In the example below
            we set a <code class="code">Zend_InfoCard</code> adapter and use it within our
            application:
        </p>
<pre class="programlisting">&lt;?php
class myAdapter implements Zend_InfoCard_Adapter_Interface 
{
    public function storeAssertion($assertionURI, $assertionID, $conditions) 
    {
        /* Store the assertion and its conditions by ID and URI */
    }
    
    public function retrieveAssertion($assertionURI, $assertionID) 
    {
        /* Retrieve the assertion by URI and ID */
    }
    
    public function removeAssertion($assertionURI, $assertionID) 
    {
        /* Delete a given assertion by URI/ID */
    }
}

$adapter  = new myAdapter();

$infoCard = new Zend_InfoCard();
$infoCard-&gt;addCertificatePair(SSL_PRIVATE, SSL_PUB);
$infoCard-&gt;setAdapter($adapter);

$claims = $infoCard-&gt;process($_POST['xmlToken']);
?&gt;</pre>
</div>
</div>
</div>
<div class="navfooter"><table width="100%" summary="Navigation footer">
<tr>
<td width="40%" align="left">
<a accesskey="p" href="zend.http.response.html">Prev</a> </td>
<td width="20%" align="center"> </td>
<td width="40%" align="right"> <a accesskey="n" href="zend.json.html">Next</a>
</td>
</tr>
<tr>
<td width="40%" align="left" valign="top">19.5. Zend_Http_Response </td>
<td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td>
<td width="40%" align="right" valign="top"> Chapter 21. Zend_Json</td>
</tr>
</table></div>
<div class="revinfo"></div>
</body>
</html>
